package md.mru.frontend.controllers;

import md.mru.core.domains.type.NodeType;
import md.mru.core.domains.type.OrderStateType;
import md.mru.core.domains.type.OrderType;
import md.mru.core.domains.type.SystemTagType;
import md.mru.core.dtos.*;
import md.mru.core.service.AdministrationService;
import md.mru.core.service.FolderService;
import md.mru.core.service.OrderService;
import md.mru.frontend.utils.FolderStateType;
import org.primefaces.context.RequestContext;
import org.primefaces.model.TreeNode;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.component.UIOutput;
import javax.faces.event.AjaxBehaviorEvent;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author sergiu.marin
 * @since 09/07/2014.
 */
@ManagedBean(name = "orderAdministrationBean")
@ViewScoped
public class OrderAdministrationBean extends BackingBean {

    private static final long serialVersionUID = -6788627955020473861L;

    @ManagedProperty(value = "#{folderService}")
    private FolderService folderService;
    @ManagedProperty(value = "#{orderService}")
    private OrderService orderService;
    @ManagedProperty(value = "#{folderAdministrationBean}")
    private FolderAdministrationBean folderAdministrationBean;
    @ManagedProperty(value = "#{treeAdministrationBean}")
    private TreeAdministrationBean treeAdministrationBean;
    @ManagedProperty(value = "#{administrationService}")
    private AdministrationService administrationService;

    private List<FolderDto> folders;
    private List<OrderTypeDto> orderTypes;
    private List<IssuerDto> issuers;
    private List<AdvancementRankDto> advancementRanks;
    private OrderDto selectedOrder;
    private Long selectedOrderTypeGroupId;
    private OrderTypeDto selectedOrderType;
    private OrderPatternDto selectedOrderPattern;
    private List<OrderTypeGroupDto> orderTypeGroups;
    Map<String, TreeNodeModelDto> transferOptions = new HashMap<>();

    private int currentLevel = 1;

    public void resetLevel2() {
        OrderTypeDto orderType = this.selectedOrder.getOrderType();
        this.selectedOrder = new OrderDto();
        this.selectedOrder.setOrderType(orderType);
    }

    public void initializeCommonOrderContent() {

    }

    public void initializeOrderPatternsContent() {
        if (this.orderTypeGroups == null) {
            this.orderTypeGroups = orderService.loadOrderTypeGroups();
            getObjectMappingConverter().mapObjectList(orderTypeGroups);
        }
        this.orderTypes = null;
        this.selectedOrderType = null;
        this.selectedOrderPattern = null;
    }

    public void onOrderTypeSelect() {
        this.selectedOrderPattern = null;
    }

    public void onOrderPatternEvent(AjaxBehaviorEvent event) {
        String value = (String) ((UIOutput) event.getSource()).getValue();
        for (OrderPatternDto orderPattern : this.selectedOrderType.getOrderPatterns()) {
            if (orderPattern.getName().equalsIgnoreCase(value)) {
                this.selectedOrderPattern = orderPattern;
                return;
            }
        }
        this.selectedOrderPattern.setName(value);
    }

    public void deleteOrderPattern() {
        this.orderService.deleteOrderPattern(selectedOrderPattern.getId());
        this.selectedOrderType.getOrderPatterns().remove(selectedOrderPattern);
        this.selectedOrderPattern = null;
    }

    public void onEditorSaveEvent() {
        if (selectedOrderPattern.getId() == 0) {
            this.selectedOrderType.getOrderPatterns().add(selectedOrderPattern);
        }
        this.orderService.saveOrderPattern(selectedOrderPattern);
        BeanUtils.addSimpleMessage("Salvat cu success.");
    }

    public String decorateTemplateHeaderValue(String value) {
        String order = "Order</br>nr. @NUMAR_ORDIN";
        return value.replace("#ORDER_NR", order);
    }

    public void newPatternHandler() {
        String orderTemplateHeader = this.decorateTemplateHeaderValue(orderService.getOrderTemplateHeader());
        this.selectedOrderPattern = new OrderPatternDto(orderTemplateHeader, selectedOrderType);
    }

    public int getCurrentLevel() {
        return currentLevel;
    }

    public void setCurrentLevel(int currentLevel) {
        this.currentLevel = currentLevel;
    }

    public void initDialogCommonComponents() {
        this.selectedOrder = new OrderDto();
        if (issuers == null) {
            issuers = orderService.loadActiveIssuers();
            this.getObjectMappingConverter().mapObjectList(issuers);
        }
    }

    public void initEmploymentOrderDialog() {
        this.selectedOrderTypeGroupId = OrderStateType.EMPLOYMENT.id;
        this.folders = this.folderService.loadFoldersByState(FolderStateType.NEW.folderStateId, FolderStateType.DISCHARGED.folderStateId);
        this.getObjectMappingConverter().mapObjectList(folders);
        this.orderTypes = orderService.loadOrderTypesByGroup(OrderStateType.EMPLOYMENT.id);
        this.getObjectMappingConverter().mapObjectList(orderTypes);
        this.initDialogCommonComponents();
    }

    public void initOrderDialogComponents(OrderStateType orderStateType) {
        switch (orderStateType) {
            case ADVANCEMENT:
                this.initAdvancementOrderDialog();
                break;
            case TRANSFER:
                /*initTransferDialog();*/
                break;
        }
        //this.getObjectMappingConverter().mapObjectList(orderTypes);
        this.initDialogCommonComponents();
    }

    public void initAdvancementOrderDialog() {
        if (advancementRanks == null) {
            advancementRanks = orderService.getAdvancementRanks();
            this.getObjectMappingConverter().mapObjectList(advancementRanks);
        }
    }

    public void confirmTransfer() {
        initOrderDialogComponents(OrderStateType.TRANSFER);
        this.orderTypes = orderService.loadOrderTypesByGroup(OrderStateType.TRANSFER.id);
        getObjectMappingConverter().mapObjectList(orderTypes);
    }

    public void onPatternOrderGroupSelect(AjaxBehaviorEvent event) {
        OrderTypeGroupDto value = (OrderTypeGroupDto) ((UIOutput) event.getSource()).getValue();
        this.orderTypes = orderService.loadOrderTypesByGroup(value.getId());
        getObjectMappingConverter().mapObjectList(orderTypes);
        this.selectedOrderType = null;
        this.selectedOrderPattern = null;
    }

    public void onOrderGroupSelect(AjaxBehaviorEvent event) {
        OrderTypeGroupDto value = (OrderTypeGroupDto) ((UIOutput) event.getSource()).getValue();
        this.selectedOrderTypeGroupId = value.getId();
        OrderStateType orderStateType = OrderStateType.valueOf(value.getId());
        if (orderStateType.equals(OrderStateType.TRANSFER)) {
            this.folderAdministrationBean.setTransferActivated(true);
            RequestContext.getCurrentInstance().addCallbackParam("transfer", true);
            this.initTransferOptions();
        } else {
            this.orderTypes = orderService.loadOrderTypesByGroup(value.getId());
            getObjectMappingConverter().mapObjectList(orderTypes);
            this.selectedOrder = new OrderDto();
            this.initOrderDialogComponents(orderStateType);
            RequestContext.getCurrentInstance().addCallbackParam("transfer", false);
            this.folderAdministrationBean.setTransferActivated(false);
        }
    }

    private void initTransferOptions() {
        transferOptions.put(SystemTagType.PREVIOUS_FUNCTION.name(), (TreeNodeModelDto) treeAdministrationBean.getSelectedTreeNode().getData());
        transferOptions.put(SystemTagType.PREVIOUS_OFFICE.name(), this.getNodeDataByType(treeAdministrationBean.getSelectedTreeNode().getParent(), NodeType.FOLDER_OFFICE));
        transferOptions.put(SystemTagType.PREVIOUS_DEPARTMENT.name(), this.getNodeDataByType(treeAdministrationBean.getSelectedTreeNode().getParent(), NodeType.FOLDER_DEPARTMENT));
        transferOptions.put(SystemTagType.PREVIOUS_SECTION.name(), this.getNodeDataByType(treeAdministrationBean.getSelectedTreeNode().getParent(), NodeType.FOLDER_SECTION));
        transferOptions.put(SystemTagType.PREVIOUS_POST.name(), this.getNodeDataByType(treeAdministrationBean.getSelectedTreeNode().getParent(), NodeType.FOLDER_POST));
    }

    public void finishOrderCreation() {
        OrderStateType orderStateType = OrderStateType.valueOf(selectedOrderTypeGroupId);
        if (orderStateType.equals(OrderStateType.EMPLOYMENT)) {
            folderAdministrationBean.setSelectedFolder(selectedOrder.getFolder());
        } else {
            this.selectedOrder.getFolders().add(folderAdministrationBean.getSelectedFolder());
        }
        //this.selectedOrder.setCreatedDate(Calendar.getInstance().getTime());
        this.selectedOrder.setId(this.orderService.saveOrder(this.selectedOrder));

        //TODO - add [created new order] event
        /*TreeAdministrationBean treeAdministrationBean = (TreeAdministrationBean) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("treeAdministrationBean");
        String nodePath = this.buildBreadCrump(treeAdministrationBean.getSelectedTreeNode());
        utilAdministrationBean.createNewEvent(new EventDto(EventType.ORDER, nodePath, selectedOrder, authenticationBean.getLoginUser().getUser()));*/

        folderAdministrationBean.changeFolderState(selectedOrder);

        this.administrateTreeModel(orderStateType);
        folderAdministrationBean.initOrderTypeGroupComponent();
    }

    public boolean showTrialPeriod() {
        return selectedOrderTypeGroupId != null && this.selectedOrder.getOrderType() != null
                && OrderStateType.EMPLOYMENT.id == selectedOrderTypeGroupId
                && OrderType.COMPETITION.id == this.selectedOrder.getOrderType().getId();
    }

    private void administrateTreeModel(OrderStateType orderStateType) {
        FolderDto folder = folderAdministrationBean.getSelectedFolder();
        switch (orderStateType) {
            case EMPLOYMENT:
                treeAdministrationBean.attachPersonToNode(folder);
                break;
            case TRANSFER:
                treeAdministrationBean.transferPersonToNewNode(folder);
                break;
            case DISCHARGED:
                treeAdministrationBean.removeFolderFromNode(folder);
                break;
            case RESTORING:
            case RECALL:
                treeAdministrationBean.activateNodeFolder(folder);
                break;
            case SUSPENDED:
            case HOLIDAY:
            case AWAY:
            case TRAINING:
            case WORK_INCAPACITY:
                treeAdministrationBean.changeNodeState(folder);
        }

    }

    public boolean checkOrderTypeState(OrderStateType type) {
        return selectedOrderTypeGroupId != null && type.id == selectedOrderTypeGroupId;
    }

    public void onOrderPatternSelect(AjaxBehaviorEvent event) {
        OrderPatternDto orderPattern = null;
        long value = Long.valueOf((String) ((UIOutput) event.getSource()).getValue());
        for (OrderPatternDto o : selectedOrder.getOrderType().getOrderPatterns()) {
            if (o.getId() == value) {
                orderPattern = o;
                break;
            }
        }
        if (orderPattern != null) {
            String orderText = this.proccessOrderTemplate(orderPattern.getPattern());
            this.selectedOrder.setOrderText(orderText);
        }
    }

    private String proccessOrderTemplate(String pattern) {
        FolderDto folder = this.selectedOrder.getFolder() != null ? this.selectedOrder.getFolder() : this.folderAdministrationBean.getSelectedFolder();
        TreeNodeModelDto function = (TreeNodeModelDto) treeAdministrationBean.getSelectedTreeNode().getData();
        TreeNodeModelDto office = this.getNodeDataByType(treeAdministrationBean.getSelectedTreeNode().getParent(), NodeType.FOLDER_OFFICE);
        TreeNodeModelDto department = this.getNodeDataByType(treeAdministrationBean.getSelectedTreeNode().getParent(), NodeType.FOLDER_DEPARTMENT);
        TreeNodeModelDto section = this.getNodeDataByType(treeAdministrationBean.getSelectedTreeNode().getParent(), NodeType.FOLDER_SECTION);
        TreeNodeModelDto post = this.getNodeDataByType(treeAdministrationBean.getSelectedTreeNode().getParent(), NodeType.FOLDER_POST);

        List<SystemTagDto> systemTags = administrationService.getSystemTags();
        for (SystemTagDto systemTag : systemTags) {
            String systemTagValue = null;
            switch (systemTag.getSystemTagType()) {
                case CHANGE_VALUE_SYSTEM_TAG:
                    systemTagValue = systemTag.getValue();
                    break;
                case CURRENT_YEAR:
                    systemTagValue = "" + Calendar.getInstance().get(Calendar.YEAR);
                    break;
                case NAME:
                    systemTagValue = folder.getFirstName() + " " + folder.getLastName();
                    break;
                case ADDRESSING_1:
                    systemTagValue = folder.getSex() == 0 ? "dlui" : "dnei";
                    break;
                case ADDRESSING_2:
                    systemTagValue = folder.getSex() == 0 ? "dl" : "dna";
                    break;
                case FUNCTION_NAME:
                    systemTagValue = this.getTreeNodeValue(function);
                    break;
                case OFFICE_LOCATION:
                    systemTagValue = office.getOfficeLocation();
                    break;
                case OFFICE_NAME:
                    systemTagValue = this.getTreeNodeValue(office);
                    break;
                case DEPARTMENT_NAME:
                    systemTagValue = this.getTreeNodeValue(department);
                    break;
                case SECTION_NAME:
                    systemTagValue = this.getTreeNodeValue(section);
                    break;
                case POST_NAME:
                    systemTagValue = this.getTreeNodeValue(post);
                    break;
                case PREVIOUS_FUNCTION:
                    systemTagValue = this.getTreeNodeValue(transferOptions.get(SystemTagType.PREVIOUS_FUNCTION.name()));
                    break;
                case PREVIOUS_OFFICE:
                    systemTagValue = this.getTreeNodeValue(transferOptions.get(SystemTagType.PREVIOUS_OFFICE.name()));
                    break;
                case PREVIOUS_DEPARTMENT:
                    systemTagValue = this.getTreeNodeValue(transferOptions.get(SystemTagType.PREVIOUS_DEPARTMENT.name()));
                    break;
                case PREVIOUS_SECTION:
                    systemTagValue = this.getTreeNodeValue(transferOptions.get(SystemTagType.PREVIOUS_SECTION.name()));
                    break;
                case PREVIOUS_POST:
                    systemTagValue = this.getTreeNodeValue(transferOptions.get(SystemTagType.PREVIOUS_POST.name()));
                    break;
                case REPLACED_PERSON:
                    systemTagValue = this.getReplacedPerson(function.getTreeFolders(), systemTag.getName());
                    break;
                case TRIAL_PERIOD:
                    systemTagValue = "" + this.selectedOrder.getTrialPeriod();
                    break;
                case GROUND:
                    systemTagValue = "" + this.selectedOrder.getGround();
                    break;
                case START_DATE:
                    systemTagValue = "" + this.formatDate(selectedOrder.getFromDate());
                    break;
                case END_DATE:
                    systemTagValue = "" + this.formatDate(selectedOrder.getToDate());
                    break;
                case EDUCATION_INSTITUTION:
                    systemTagValue = "" + this.selectedOrder.getEducationInstitutionName();
                    break;
                case TRANSFER_FROM:
                    systemTagValue = this.selectedOrder.getTransferFrom();
                    break;
                case DOC_NUMBER:
                    systemTagValue = this.selectedOrder.getDocNumber();
                    break;
                case DOC_DATE:
                    systemTagValue = "" + this.formatDate(selectedOrder.getDocDate());
                    break;
                case DOC_ISSUED_BY:
                    systemTagValue = this.selectedOrder.getIssuedBy();
                    break;
                case RANK:
                    systemTagValue = this.getAdvancementRankValue(selectedOrder.getAdvancementRank(), systemTag.getName());
                    folder.setAdvancementRank(selectedOrder.getAdvancementRank());
                    break;
                case RANK_INITIAL:
                    systemTagValue = this.getAdvancementRankValue(folder.getAdvancementRank(), systemTag.getName());
                    folder.setAdvancementRank(selectedOrder.getAdvancementRank());
                    break;
                case TO_LOCATION:
                    systemTagValue = this.selectedOrder.getLocation();
                    break;
                case REASON:
                    systemTagValue = this.selectedOrder.getReason();
                    break;
            }
            if (systemTagValue == null) {
                systemTagValue = systemTag.getName();
            }
            pattern = pattern.replace(systemTag.getName(), systemTagValue);
        }
        return pattern.replaceAll(",[\\s]*,", ",");
    }

    private String getReplacedPerson(Set<TreeFolderDto> treeFolders, String name) {
        for (TreeFolderDto folder : treeFolders) {
            if (folder.getId().getFolder().getFolderState().getId() == FolderStateType.MATERNITY_LEAVE.folderStateId) {
                return folder.getId().getFolder().getFirstName() + " " + folder.getId().getFolder().getLastName();
            }
        }
        return name;
    }

    private String getTreeNodeValue(TreeNodeModelDto model) {
        if (model != null) {
            return model.getName();
        } else {
            return "";
        }
    }

    private String getAdvancementRankValue(AdvancementRankDto rank, String tagName) {
        if (rank != null) {
            return rank.getName();
        } else {
            return tagName;
        }
    }

    public String formatDate(Date date) {
        if (date == null) {
            return null;
        }
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd.MM.yyyy");
        return simpleDateFormat.format(date);
    }

    private TreeNodeModelDto getNodeDataByType(TreeNode treeNode, NodeType nodeType) {
        TreeNodeModelDto nodeData = (TreeNodeModelDto) treeNode.getData();
        if (nodeData.getTreeNodeType().getNodeType().equals(NodeType.FOLDER)) {
            return null;
        }
        if (nodeData.getTreeNodeType().getNodeType().equals(nodeType)) {
            return nodeData;
        } else {
            return this.getNodeDataByType(treeNode.getParent(), nodeType);
        }
    }

    public boolean checkOrderType(OrderType type) {
        return selectedOrder.getOrderType() != null && type.id == selectedOrder.getOrderType().getId();
    }

    public boolean showRangeDate() {
        return OrderStateType.HOLIDAY.id == selectedOrderTypeGroupId
                || OrderStateType.SUSPENDED.id == selectedOrderTypeGroupId
                || OrderStateType.AWAY.id == selectedOrderTypeGroupId
                || OrderStateType.TRAINING.id == selectedOrderTypeGroupId
                || OrderStateType.WORK_INCAPACITY.id == selectedOrderTypeGroupId
                || selectedOrder.getOrderType() != null &&
                (OrderType.PRACTICE.id == selectedOrder.getOrderType().getId()
                        || OrderType.PAID_MATERNITY_LEAVE.id == selectedOrder.getOrderType().getId()
                        || OrderType.UNPAID_MATERNITY_LEAVE.id == selectedOrder.getOrderType().getId()
                        || OrderType.VACATION_NOT_PAID.id == selectedOrder.getOrderType().getId()
                        || OrderType.VACATION_PAID.id == selectedOrder.getOrderType().getId()
                        || OrderType.STUDY_VACATION.id == selectedOrder.getOrderType().getId()
                        || OrderType.DETACHMENT.id == selectedOrder.getOrderType().getId()
                        || OrderType.DISPLACEMENT.id == selectedOrder.getOrderType().getId());
    }

    public boolean showToDate() {
        return OrderStateType.SUSPENDED.id == selectedOrderTypeGroupId
                || OrderStateType.HOLIDAY.id == selectedOrderTypeGroupId
                || OrderStateType.SANCTIONS.id == selectedOrderTypeGroupId
                || OrderStateType.AWAY.id == selectedOrderTypeGroupId
                || OrderStateType.TRAINING.id == selectedOrderTypeGroupId
                || OrderStateType.WORK_INCAPACITY.id == selectedOrderTypeGroupId
                || selectedOrder.getOrderType() != null &&
                (OrderType.PRACTICE.id == selectedOrder.getOrderType().getId()
                        || OrderType.PAID_MATERNITY_LEAVE.id == selectedOrder.getOrderType().getId()
                        || OrderType.UNPAID_MATERNITY_LEAVE.id == selectedOrder.getOrderType().getId()
                        || OrderType.VACATION_NOT_PAID.id == selectedOrder.getOrderType().getId()
                        || OrderType.VACATION_PAID.id == selectedOrder.getOrderType().getId()
                        || OrderType.STUDY_VACATION.id == selectedOrder.getOrderType().getId());
    }

    public boolean displayLocation() {
        return selectedOrder.getOrderType() != null
                && (OrderType.DETACHMENT.id == selectedOrder.getOrderType().getId()
                || OrderType.DISPLACEMENT.id == selectedOrder.getOrderType().getId());
    }

    public boolean displayGrounds() {
        return OrderStateType.ADVANCEMENT.id == selectedOrderTypeGroupId
                || OrderStateType.TRANSFER.id == selectedOrderTypeGroupId
                || OrderStateType.TRANSFER.id == selectedOrderTypeGroupId
                || OrderStateType.SUSPENDED.id == selectedOrderTypeGroupId
                || OrderStateType.AWAY.id == selectedOrderTypeGroupId
                || (selectedOrder.getOrderType() != null
                && (OrderType.PRACTICE.id == selectedOrder.getOrderType().getId()
                || OrderType.TRANSFER.id == selectedOrder.getOrderType().getId()
                || OrderType.STUDY_VACATION.id == selectedOrder.getOrderType().getId()
                || OrderType.DISPLACEMENT.id == selectedOrder.getOrderType().getId()
                || OrderType.DETACHMENT.id == selectedOrder.getOrderType().getId()));
    }

    public boolean displayEducationInstitution() {
        return selectedOrder.getOrderType() != null
                && (OrderType.PRACTICE.id == selectedOrder.getOrderType().getId()
                || OrderType.STUDY_VACATION.id == selectedOrder.getOrderType().getId());
    }

    public boolean showNotes() {
        return OrderStateType.DISCHARGED.id == selectedOrderTypeGroupId
                || OrderStateType.SUSPENDED.id == selectedOrderTypeGroupId
                || OrderStateType.AWAY.id == selectedOrderTypeGroupId
                || OrderStateType.RESTORING.id == selectedOrderTypeGroupId
                || OrderStateType.RECALL.id == selectedOrderTypeGroupId
                || OrderStateType.HOLIDAY_SUPPLEMENT.id == selectedOrderTypeGroupId;
    }

    public String getOrderDialogTitle() {
        if (selectedOrderTypeGroupId != null) {
            return OrderStateType.valueOf(selectedOrderTypeGroupId).title;
        }
        return null;
    }

    public List<FolderDto> getFolders() {
        return folders;
    }

    public List<OrderTypeDto> getOrderTypes() {
        return orderTypes;
    }

    public List<IssuerDto> getIssuers() {
        return issuers;
    }

    public List<AdvancementRankDto> getAdvancementRanks() {
        return advancementRanks;
    }

    public OrderDto getSelectedOrder() {
        return selectedOrder;
    }

    public void setFolderService(FolderService folderService) {
        this.folderService = folderService;
    }

    public void setOrderService(OrderService orderService) {
        this.orderService = orderService;
    }

    public void setFolderAdministrationBean(FolderAdministrationBean folderAdministrationBean) {
        this.folderAdministrationBean = folderAdministrationBean;
    }

    public String getOrderTemplate() {
        if (selectedOrderPattern == null) {
            return null;
        }
        return this.selectedOrderPattern.getPattern();
    }

    public void setOrderTemplate(String value) {
        this.selectedOrderPattern.setPattern(value);
    }

    public void setTreeAdministrationBean(TreeAdministrationBean treeAdministrationBean) {
        this.treeAdministrationBean = treeAdministrationBean;
    }

    public List<OrderTypeGroupDto> getOrderTypeGroups() {
        return orderTypeGroups;
    }

    public OrderTypeDto getSelectedOrderType() {
        return selectedOrderType;
    }

    public void setSelectedOrderType(OrderTypeDto selectedOrderType) {
        this.selectedOrderType = selectedOrderType;
    }


    public OrderPatternDto getSelectedOrderPattern() {
        return selectedOrderPattern;
    }

    public void setSelectedOrderPattern(OrderPatternDto selectedOrderPattern) {
        this.selectedOrderPattern = selectedOrderPattern;
    }

    public void setAdministrationService(AdministrationService administrationService) {
        this.administrationService = administrationService;
    }
}
